package com.xuecheng.content.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.CourseBaseDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.CourseMarketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;


@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase>
        implements CourseBaseService {
    @Autowired
    private CourseMarketService courseMarketService;
    /*
    *  步骤分析:
    *   1.是否需要开启事务
    *   2.构建查询条件对象LambdaQueryWrapper
    *   3.判断关键数据
    *           分页数据
    *           查询条件
    *   4.构建mp分页对象
    *
    5.将结果封装到pagevo中
    */
    @Override
    public PageVO queryCourseList(PageRequestParams params, QueryCourseModel model, Long companyId) {
        //1.是否需要开启事务
        // 查询无需开启事务
        // 2.判断关键数据
        //      分页数据
        //      查询条件

        // 2.1 判断分页数据
        Long pageNo = params.getPageNo();
        Integer pageSize = params.getPageSize();

        if (ObjectUtils.isEmpty(pageNo) || pageNo < 0) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }

        if (ObjectUtils.isEmpty(pageSize) || pageSize < 0) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        // 2.2.构建查询条件对象LambdaQueryWrapper
        // 完成第四部中的构建查询条件
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

        // 完整版
        // select * from course_base where name = ? and auditStatus = ? and companyId = ?
        // if (StringUtil.isNotBlank(model.getCourseName())) {
        //     queryWrapper.eq(CourseBase::getName,model.getCourseName());
        // }
        //
        // if (StringUtil.isNotBlank(model.getAuditStatus())) {
        //     queryWrapper.eq(CourseBase::getAuditStatus,model.getAuditStatus());
        // }

        // 简版
        queryWrapper.like(StringUtil.isNotBlank(model.getCourseName()),CourseBase::getName,model.getCourseName());
        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()),CourseBase::getAuditStatus,model.getAuditStatus());
        queryWrapper.eq(CourseBase::getCompanyId,companyId);
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCode());


        // 3.构建mp分页对象
        Page<CourseBase> page = new Page<>(params.getPageNo(),params.getPageSize());


        // 5.查询数据
        Page<CourseBase> pageResult = this.page(page, queryWrapper);

        // 获得当前页的集合数据
        List<CourseBase> records = pageResult.getRecords();

        // 查询数据的总记录数
        long total = pageResult.getTotal();


        // 将po数据转为dto数据
        List<CourseBaseDTO> dtos = Collections.EMPTY_LIST;


        if (!(CollectionUtils.isEmpty(records))) {
            dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }



        // 6.获得数据并封装返回结果
        //      封装PageVo数据
        PageVO pageVO = new PageVO(dtos, total, params.getPageNo(), params.getPageSize());


        return pageVO;
    }
    /*
     *        新增业务分析:
     *               1.是否开启事务
     *                   除了查询不需要开启外,其他都需要开启事务
     *               2.判断关键数据
     *                      课程基础信息
     *                           关键数据:表中内容的必要数据,无此数据代表数据不完整
     *                           关键数据来源:
     *                                   1. 数据库约束
     *                                           不会空的字段
     *                                   2.前端页面中的必要数据
     *                                           在浏览器中有小红点标识
     *                                   3.接口文档. Yapi
     *                                           之后讲 ,会体现出必要数据
     *               3.将dto转化成po 并赋值审核状态的默认值
     *                      保存: 未提交
     *               4.保存数据
     *                   4.1 保存课程基本信息
     *                           判断保存结果
     *                   4.2 保存课程营销信息
     *                           判断保存结果
     *               5.将数据库最新数据转化为dto并返回
     * */
    @Transactional
    public CourseBaseDTO createCourseBase(CourseBaseDTO dto) {

        // 2 判断关键数据
        verifyCourseMsg(dto);
        //3 将dto数据转化成po
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);
        //保存: 状态  未提交
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());
        // 4 保存数据
        //   如果mp对数据保存成功后，会将保存成功在数据库中的id值返回给courseBase中
        // 4.1 保存课程基本信息  并 判断
        boolean baseResult = this.save(courseBase);
        if (!baseResult) {
            throw new RuntimeException("保存课程基础信息失败!!!");
        }
        //4.2 保存课程营销信息
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setCourseId(courseBase.getId());
        courseMarket.setCharge(dto.getCharge());
        //判断课程是否收费
        // 1 如果免费则无需给price赋值
        // 2 如果收费则必须给price赋值
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {

            if (ObjectUtils.isEmpty(dto.getPrice())) {
                throw new RuntimeException("收费课程的价格不能为空!!!");
            }
            courseMarket.setPrice(dto.getPrice().floatValue());
        }
        boolean marketResult = courseMarketService.save(courseMarket);
        if (!marketResult) {
            throw new RuntimeException("保存课程营销信息失败!!!");
        }
        //5 将数据库的最新数据转为dto并返回
        CourseBaseDTO baseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        baseDTO.setCharge(dto.getCharge());
        baseDTO.setPrice(dto.getPrice());
        return baseDTO;
    }
    /*
    * 业务分析:
    *       1 是否需要开启事务
    *       2 判断关键数据
    *               courseId  companyId
    *       3 判断业务数据
    *               课程基础信息
    *                       课程是否是同一家机构
    *                       判断课程是否已删除
    *       4 将数据转为dto返回
    *
    * */
    public CourseBaseDTO getByCourseId(Long courseBaseId, Long companyId) {
        //1 判断关键数据
        if (ObjectUtils.isEmpty(courseBaseId) || ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException(CommonErrorCode.E_100101.getDesc());
        }
        //2 判断业务数据
        //2.1 根据id查询后的机构的id进行比较(比较麻烦) 好理解
        CourseBase courseBase = this.getById(courseBaseId);
        if (!(ObjectUtils.nullSafeEquals(companyId,courseBase.getCompanyId()))) {
            throw new RuntimeException(CommonErrorCode.E_403000.getDesc());
        }
        // 不好理解
        //CourseBase courseBase1 = getCourseBaseAndLogicVerify(courseBaseId, companyId);
        //3 将数据转化成dto并返回
        CourseBaseDTO dto = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        LambdaQueryWrapper<CourseMarket> marketQueryWrapper = new LambdaQueryWrapper<>();
        marketQueryWrapper.eq(CourseMarket::getCourseId, courseBaseId);

        CourseMarket market = courseMarketService.getOne(marketQueryWrapper);

        dto.setPrice(new BigDecimal(market.getPrice().toString()));
        dto.setCharge(market.getCharge());
        return dto;
    }
    /*
     * 业务分析：
     *          是否需要开启事务
     *   1.判断关键数据
     *      参考添加的判断
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否是同一家教学机构
     *           判断课程是否被删除
     *           判断课程的审核状态
     *               只有 未提交、审核未通过 才可以修改数据
     *   3.转换dto数据为po数据
     *   4.修改数据
     *       课程基础信息
     *       课程营销信息
     *
     *   5.将最新数据返回给dto
     * */
    @Transactional
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {
        //1 判断关键数据
        verifyCourseMsg(dto);
        // 新增不需要id  所有id需要单独判断
        if (ObjectUtils.isEmpty(dto.getCourseBaseId())) {
            throw new RuntimeException("修改课程id不能为空");
        }
        //2 判断业务数据
        CourseBase courseBase = getCourseBaseAndLogicVerify(dto.getCourseBaseId(), dto.getCompanyId());
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("课程审核状态异常");
        }
        //3 转换数据  dto- po
        CourseBase po = CourseBaseConvert.INSTANCE.dto2entity(dto);
        //4 修改数据
            // 课程基础信息
        boolean updateById = this.updateById(po);
        if (!updateById) {
            throw new RuntimeException("修改课程基础信息失败");
        }
            // 课程营销数据
        LambdaUpdateWrapper<CourseMarket> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseMarket::getCharge,dto.getCharge());
        float price = 0f;
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {
            price = dto.getPrice().floatValue();
        }
        updateWrapper.set(CourseMarket::getPrice, price);


        updateWrapper.eq(CourseMarket::getCourseId,dto.getCourseBaseId());

        boolean marketResult = courseMarketService.update(updateWrapper);

        if (!marketResult) {
            throw new RuntimeException("修改课程营销信息失败");
        }
        // 5 将最新数据返回给dto
        CourseBase resultPO = this.getById(dto.getCourseBaseId());

        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(resultPO);

        resultDTO.setCharge(dto.getCharge());
        resultDTO.setPrice(dto.getPrice());
        return resultDTO;
    }
    /*
    * 业务分析:
    *       1 是否需要开启事务
    *           除了查询都需要
    *       2 判断关键数据
    *       3 判断课程基本信息
    *                   判断课程的状态
    *                   判断是否是同一家机构
    *       4 不需要返回
    *
    * */
    @Transactional
    public void deleteCourseBase(Long courseBaseId, Long companyId) {
            //2.判断关键数据的合法性
        if (ObjectUtils.isEmpty(courseBaseId) ||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //3.判断关键数据
        //3.1 获得课程基础信息
        CourseBase courseBase = getById(courseBaseId);

        verifyPO(companyId, courseBase);


        //3.2 判断课程的审核状态
        String auditStatus = courseBase.getAuditStatus();

        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }

        // 4.修改课程信息状态值
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getStatus,CommonEnum.DELETE_FLAG.getCodeInt());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());

        updateWrapper.eq(CourseBase::getId, courseBase.getId());

        boolean result = update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }
    private void verifyPO(Long companyId, CourseBase courseBase) {
        // 判断课程数据是否存在
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
    }
    private void verifyCourseMsg(CourseBaseDTO dto) {
        //2.判断关键数据
        //     课程基础信息
        // companyId  name  mt st  grade teachmode  users  pic（后期来判断）

        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            // 业务异常：程序员在做业务判断时，数据有问题。
            // 异常：
            //    1.终止程序
            //    2.传递错误信息
            //    3.使用运行时异常来抛出
            //        运行时异常不需在编译期间处理
            //throw new RuntimeException("公司id不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120000);
        }

        if (StringUtil.isBlank(dto.getName())) {
           //throw new RuntimeException("课程名称不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }

        if (StringUtil.isBlank(dto.getMt())) {
            //throw new RuntimeException("课程大分类不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120002);
        }

        if (StringUtil.isBlank(dto.getSt())) {
            //throw new RuntimeException("课程小分类不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }

        if (StringUtil.isBlank(dto.getGrade())) {
            //throw new RuntimeException("课程等级不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }

        if (StringUtil.isBlank(dto.getTeachmode())) {
            //throw new RuntimeException("课程教学模式不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120006);
        }

        if (StringUtil.isBlank(dto.getUsers())) {
            //throw new RuntimeException("使用人群不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120018);

        }

        if (StringUtil.isBlank(dto.getCharge())) {
            //throw new RuntimeException("课程收费不能为空");
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
    }
    private CourseBase getCourseBaseAndLogicVerify(Long courseId, Long companyId) {
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseBase::getId, courseId);
        queryWrapper.eq(CourseBase::getCompanyId, companyId);

        CourseBase courseBase = this.getOne(queryWrapper);

        if (ObjectUtils.isEmpty(courseBase)) {
            throw new RuntimeException("课程基础信息不存在");
        }


        // 2.2 判断课程是否已删除
        Integer status = courseBase.getStatus();
        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(status)) {
            throw new RuntimeException("课程基础信息已删除");
        }
        return courseBase;
    }
    /*
    * 业务分析:
    *       1 是否需要开启事务
    *               需要
    *       2 判断关键数据
    *       3 判断业务数据
    *           课程基本信息
    *               判断课程是否存在
    *               判断是否是同一家机构
    *               判断是否删除
    *               判断审核状态
    *       4 修改课程的审核状态
    *               教学机构-->已提交
    *       5 判断修改结果
    * */
    public void commitCourseBase(Long courseId, Long companyId) {
            //2 判断关键数据  courseid companyid
        if (ObjectUtils.isEmpty(courseId) ||
          ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
            //3 判断业务数据
        //     课程基本信息
        //         判断课程是否存在
        //         判断是否是同一家机构
        //         判断是否删除
        //         判断审核状态
        getReasonableCourseBase(courseId,companyId);
        // 4 修改审核状态
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus,CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        updateWrapper.set(CourseBase::getChangeDate,LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId,courseId);
        boolean result = this.update(updateWrapper);
        //5 判断修改结果
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }
    private CourseBase getReasonableCourseBase(Long courseId, Long companyId) {
        CourseBase courseBase = getCourseBaseAndLogicVerify(courseId, companyId);

        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }

        return courseBase;
    }
    @Transactional
    public PageVO<CourseBaseDTO> queryCourseBaseList(PageRequestParams params, QueryCourseModel model, Long companyId) {
        //2.判断数据
        //2.1 分页查询
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }
        //创建LambdaQueryWrapper对象
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        //2.2 判断条件查询
        if (StringUtil.isNotBlank(model.getAuditStatus())) {
            //添加审核状态条件
            queryWrapper.eq(CourseBase::getAuditStatus, model.getAuditStatus());
        }
        if (StringUtil.isNotBlank(model.getCourseName())) {
            //添加课程名条件
            queryWrapper.eq(CourseBase::getName, model.getCourseName());
        }
        //判断公司名是否存在
        if (!ObjectUtils.isEmpty(companyId)) {
            queryWrapper.eq(!(ObjectUtils.isEmpty(companyId)),CourseBase::getCompanyId,companyId);

        }
        /*//添加对教学机构的查询条件
        queryWrapper.eq(CourseBase::getCompanyId, companyId);*/
           // queryWrapper.eq(CourseBase::getCompanyName,model.getCourseName());
        //3.创建分页数据
        Page<CourseBase> page = new Page<>(params.getPageNo(), params.getPageSize());
        //4.根据分页和查询调价查询list数据

        Page<CourseBase> pageResult = this.page(page, queryWrapper);
        List<CourseBase> records = pageResult.getRecords();
        long total = pageResult.getTotal();
        // 将po  数据转为dot数据
        List<CourseBaseDTO> dots = Collections.EMPTY_LIST;
        if (!(CollectionUtils.isEmpty(records))) {
            List<CourseBaseDTO> dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }
        //5.将结果封装到pagevo中
        PageVO pageVO = new PageVO(records, total, params.getPageNo(), params.getPageSize());
        return pageVO;
    }
        /*
    *       业务分析:
    *           1 是否需要开启事务  需要
    *           2 判断关键数据
    *               courseId auditStatus auditMind
    *           3 判断关键业务
    *               课程基本信息
    *                   课程是否存在
    *                    课程是否删除
    *                       判断审核状态
    *           4 修改课程审核状态
    *            运营平台：审核通过、审核未通过
     *           前提：课程的状态必须为已提交
    *           5 判断修改结果
    *
    *
    * */
    @Transactional
    public void approveCourse(CourseBaseDTO dto) {
        // 判断关键数据

        String auditStatus = dto.getAuditStatus();
        if (ObjectUtils.isEmpty(dto.getCourseBaseId())||
                StringUtil.isBlank(auditStatus)||
                StringUtil.isBlank(dto.getAuditMind())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        CourseBase courseBase = this.getById(dto.getCourseBaseId());

        // 判断课程是否存在
        ExceptionCast.cast(ObjectUtils.isEmpty(courseBase),ContentErrorCode.E_120013);

        // 判断课程是否删除
        ExceptionCast.cast(CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus()),
                ContentErrorCode.E_120019);

        // 判断课程审核状态：只能是已提交
        ExceptionCast.cast(!(CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus())),
                ContentErrorCode.E_120015);

        // 2.2  判断运营平台的审核状态
        //      运营平台：只能是 审核通过或审核未通过
        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().equals(auditStatus)||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100108);
        }


        // 3.修改课程审核的数据
        //     修改CourseBase表
        //         audtiStatus
        //         auditMind
        //         auditNum
        //         changeDate
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, auditStatus);
        updateWrapper.set(CourseBase::getAuditMind, dto.getAuditMind());
        updateWrapper.set(CourseBase::getAuditNums, courseBase.getAuditNums()+1);
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, courseBase.getId());
        boolean result = this.update(updateWrapper);
        // 判断修改结果
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }
}

